home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 23 / CU Amiga - Super CD-ROM 23 (June 1998).iso / CUCD / Sound / PlayMF_VU / PianoMeter / Source / vu.c < prev   
Encoding:
C/C++ Source or Header  |  1998-03-19  |  29.0 KB  |  1,275 lines

  1.  
  2. /*---------------------------------------------------------------*/
  3. /* vu.c - graphical MIDI note visualisation using BOOPSI classes */
  4. /*                 ® 1998 by Christian Buchner                   */
  5. /*---------------------------------------------------------------*/
  6.  
  7. /* Library bases */
  8.  
  9. struct ExecBase            *SysBase;
  10. struct DosLibrary        *DOSBase;
  11. struct GfxBase            *GfxBase;
  12. struct IntuitionBase    *IntuitionBase;
  13. struct Library             *GadToolsBase;
  14. struct Library            *UtilityBase;
  15. struct Library            *CamdBase;
  16.  
  17. /* Workbench or not? */
  18.  
  19. BOOL WBMode = FALSE;
  20.  
  21. /* Prototypes */
  22.  
  23. LONG ShellInterface(void);
  24. LONG WBInterface(struct Process *MyProc);
  25.  
  26. BOOL WindowLayout(struct Screen *scr, WORD *ww, WORD *wh, WORD *minw, WORD *minh, WORD *maxw, WORD *maxh, ULONG *Octaves);
  27. BOOL CreateOrLayoutGadgets(struct Screen *scr, struct Gadget **FirstGad, struct Gadget **PianoGad, struct Gadget **ChanLedGad, WORD ww, WORD wh, ULONG *Octaves);
  28.  
  29. LONG PianoMeter(UBYTE *linkname, ULONG Octaves, LONG WinX, LONG WinY);
  30. void MainLoop(UBYTE *linkname, struct Window *Window, struct Gadget **FirstGad, struct Gadget **PianoGad, struct Gadget **ChanLedGad, struct MidiNode **midi, struct MidiLink **link, ULONG *Octaves);
  31. BOOL OpenLibs(void);
  32. void CloseLibs(void);
  33. LONG DoCustomClassMethod (struct IClass *cl, Msg msg);
  34. LONG __stdargs Message(UBYTE *Msg,UBYTE *Options,...);
  35. void __stdargs _XCEXIT(LONG lcode);
  36.  
  37.                               /* SPrintf.a */
  38. APTR __stdargs SPrintf(char *, const char *, ...);
  39. APTR __stdargs VSprintf(char *, const char *, va_list);
  40.  
  41.  
  42. /* CAM Library data and protos */
  43.  
  44. struct MidiNode *CreateMidi(Tag tag, ...);
  45. BOOL SetMidiAttrs(struct MidiNode *mi, Tag tag, ...);
  46. struct MidiLink *AddMidiLink(struct MidiNode *mi, LONG type, Tag tag, ...);
  47. BOOL SetMidiLinkAttrs(struct MidiLink *mi, Tag tag, ...);
  48.  
  49.  
  50. /* Some defines */
  51.  
  52. /* the opposite of noteon() */
  53. #define noteoff(m) ( voicemsg(m,MS_NoteOff) || (voicemsg(m,MS_NoteOn) && (!(m)->mm_Data2)) )
  54.  
  55. #define offsetof(s, m)  (size_t)(&(((s *)0)->m))
  56. #define MIN(a,b)    ((a) <= (b) ? (a) : (b))
  57. #define elementsof(a)  ((sizeof(a) / sizeof(a[0])))
  58.  
  59.  
  60. /* Intuition structures */
  61.  
  62. enum
  63. {
  64.     Menu_Ignore,
  65.     Menu_Link,
  66.     Menu_Save,
  67.     Menu_About,
  68.     Menu_Quit,
  69.     Menu_Release,
  70. };
  71.  
  72.  
  73. struct NewMenu VUNewMenu[]=
  74. {
  75.     /* nm_Type    nm_Label            nm_CommKey    nm_Flags            nm_MutualExclude    nm_UserData */
  76.     NM_TITLE,    "Project",            NULL,        0,                    0,                    (APTR)Menu_Ignore,
  77.     NM_ITEM,    "MIDI Link...",        "L",        0,                    0,                    (APTR)Menu_Link,
  78.     NM_ITEM,    "Save Config",        "S",        0,                    0,                    (APTR)Menu_Save,
  79.     NM_ITEM,    NM_BARLABEL,        NULL,        0,                    0,                    (APTR)Menu_Ignore,
  80.     NM_ITEM,    "About",            "?",        0,                    0,                    (APTR)Menu_About,
  81.     NM_ITEM,    NM_BARLABEL,        NULL,        0,                    0,                    (APTR)Menu_Ignore,
  82.     NM_ITEM,    "Quit",                "Q",        0,                    0,                    (APTR)Menu_Quit,
  83.     NM_TITLE,    "MIDI",                NULL,        0,                    0,                    (APTR)Menu_Ignore,
  84.     NM_ITEM,    "Release Notes",    "N",        0,                    0,                    (APTR)Menu_Release,
  85.     NM_END,        NULL,                NULL,        0,                    0,                    (APTR)Menu_Ignore,
  86. };
  87.  
  88.  
  89.  
  90. /*--------------*/
  91. /* Startup code */
  92. /*--------------*/
  93.  
  94. LONG __saveds mymain(void)
  95. {
  96.     LONG ReturnCode;
  97.     
  98.     struct    Process *MyProc;
  99.     
  100.     SysBase = *((struct ExecBase**)(0x4));
  101.     
  102.     MyProc = (struct Process*) FindTask(NULL);
  103.     
  104.     if (!MyProc->pr_CLI)
  105.     {
  106.         WBMode = TRUE;
  107.         ReturnCode = WBInterface(MyProc);
  108.     }
  109.     else
  110.     {
  111.         ReturnCode = ShellInterface();
  112.     }
  113.     
  114.     return(ReturnCode);
  115. }
  116.  
  117.  
  118.  
  119. /*---------------------*/
  120. /* Workbench Interface */
  121. /*---------------------*/
  122.  
  123. LONG WBInterface(struct Process *MyProc)
  124. {
  125.     struct WBStartup *wbmsg;
  126.     
  127.     LONG ReturnCode;
  128.     
  129.     WaitPort(&MyProc->pr_MsgPort);
  130.     
  131.     if (wbmsg = (struct WBStartup*)GetMsg(&MyProc->pr_MsgPort))
  132.     {
  133.         if (OpenLibs())
  134.         {
  135.             ReturnCode = PianoMeter("out.0", 5, 100, 200);
  136.             
  137.             CloseLibs();
  138.         }
  139.         Forbid();
  140.         ReplyMsg((struct Message*)wbmsg);
  141.     }
  142.     return(ReturnCode);
  143. }
  144.  
  145.  
  146.  
  147. /*-----------------*/
  148. /* Shell Interface */
  149. /*-----------------*/
  150.  
  151. LONG  ShellInterface(void)
  152. {
  153.     LONG ReturnCode = RETURN_ERROR;
  154.     
  155.     UBYTE *linkname = "out.0";
  156.     
  157.     ULONG Octaves = 5;
  158.     LONG WinX = 100;
  159.     LONG WinY = 200;
  160.     
  161.     if (OpenLibs())
  162.     {
  163.         /* CLI argument parsing */
  164.         
  165.         struct    ArgArray
  166.         {
  167.             UBYTE *aa_Link;
  168.             ULONG *aa_Octaves;
  169.             ULONG *aa_WinX;
  170.             ULONG *aa_WinY;
  171.         } AA = {NULL, NULL, NULL, NULL};
  172.         
  173.         static UBYTE    *Template = "LINK/K,OCT=OCTAVES/K/N,WINX/K/N,WINY/K/N";
  174.         struct RDArgs *RDArgs;
  175.         
  176.         ReturnCode = RETURN_FAIL;
  177.         
  178.         if (RDArgs=ReadArgs(Template, (LONG *)&AA, 0))
  179.         {
  180.             if (AA.aa_Link) linkname = AA.aa_Link;
  181.             if (AA.aa_Octaves) Octaves = *AA.aa_Octaves;
  182.             if (Octaves < 1) Octaves = 1;
  183.             if (Octaves > 11) Octaves = 11;
  184.             if (AA.aa_WinX) WinX= *AA.aa_WinX;
  185.             if (AA.aa_WinY) WinY= *AA.aa_WinY;
  186.             
  187.             ReturnCode = PianoMeter(linkname, Octaves, WinX, WinY);
  188.             
  189.             FreeArgs(RDArgs);
  190.         }
  191.         else
  192.         {
  193.             PrintFault(IoErr(),"vu");
  194.         }
  195.         CloseLibs();
  196.     }
  197.     return(ReturnCode);
  198. }
  199.  
  200.  
  201.  
  202. /*-----------------------------------*/
  203. /* MIDI/Window/Gadget initialisation */
  204. /*-----------------------------------*/
  205.  
  206. LONG PianoMeter(UBYTE *linkname, ULONG Octaves, LONG WinX, LONG WinY)
  207. {
  208.     LONG ReturnCode = RETURN_FAIL;
  209.     
  210.     struct Screen *scr;
  211.     APTR VisualInfo;
  212.     struct Window *Window;
  213.     struct Menu   *Menu;
  214.     
  215.     struct Gadget *FirstGad = NULL;
  216.     
  217.     struct Gadget *PianoGad = NULL;
  218.     
  219.     UWORD i;
  220.     struct Gadget *ChanLedGad[16]={    NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
  221.                                     NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL };
  222.     
  223.     WORD ww, wh;
  224.     WORD minw, minh;
  225.     WORD maxw, maxh;
  226.     
  227.     struct MidiNode *midi;
  228.     struct MidiLink *link;
  229.     UBYTE buffer[80];
  230.     
  231.     struct Task *MyTask;
  232.     BYTE OldPri;
  233.     
  234.     if( !_initclasses() )
  235.     {
  236.         Message("Unable to initialize the classes.",NULL);
  237.     }
  238.     else
  239.     {
  240.         if (scr = LockPubScreen(NULL))
  241.         {
  242.             if (!(VisualInfo = GetVisualInfo(scr, TAG_DONE)))
  243.             {
  244.                 Message("No visual info!",NULL);
  245.             }
  246.             else
  247.             {
  248.                 if (!(WindowLayout(scr, &ww, &wh, &minw, &minh, &maxw, &maxh, &Octaves)))
  249.                 {
  250.                     Message("Couldn't layout window!",NULL);
  251.                 }
  252.                 else
  253.                 {
  254.                     if (!(Window = OpenWindowTags( NULL,
  255.                             WA_PubScreen, scr,
  256.                             WA_Title, "Piano Meter",
  257.                             WA_Left, WinX,
  258.                             WA_Top, WinY,
  259.                             WA_InnerWidth, (ULONG)ww,
  260.                             WA_InnerHeight, (ULONG)wh,
  261.                             WA_GimmeZeroZero, TRUE,
  262.                             WA_DepthGadget, TRUE,
  263.                             WA_SizeGadget, TRUE,
  264.                             WA_SizeBBottom, TRUE,
  265.                             WA_CloseGadget, TRUE,
  266.                             WA_DragBar, TRUE,
  267.                             WA_IDCMP, IDCMP_CLOSEWINDOW|IDCMP_GADGETDOWN|IDCMP_GADGETUP|IDCMP_SIZEVERIFY|IDCMP_NEWSIZE|IDCMP_MENUPICK,
  268.                             WA_SimpleRefresh, TRUE,
  269.                             WA_NoCareRefresh, TRUE,
  270.                             WA_NewLookMenus, TRUE,
  271.                             TAG_DONE ) ))
  272.                     {
  273.                         Message("Couldn't open window!",NULL);
  274.                     }
  275.                     else
  276.                     {
  277.                         ww = Window->Width  - Window->BorderLeft-Window->BorderRight ;
  278.                         wh = Window->Height - Window->BorderTop -Window->BorderBottom;
  279.                         
  280.                         Window->MinWidth  = minw + Window->BorderLeft+Window->BorderRight;
  281.                         Window->MinHeight = minh + Window->BorderTop +Window->BorderBottom;
  282.                         Window->MaxWidth  = maxw + Window->BorderLeft+Window->BorderRight;
  283.                         Window->MaxHeight = maxh + Window->BorderTop +Window->BorderBottom;
  284.                         
  285.                         if (!(Menu=(struct Menu *)CreateMenus(VUNewMenu, TAG_DONE)))
  286.                         {
  287.                             Message("Failed to create intuition menu.",NULL);
  288.                         }
  289.                         else
  290.                         {
  291.                             LayoutMenus(Menu, VisualInfo, GTMN_NewLookMenus, TRUE, TAG_DONE);
  292.                             SetMenuStrip(Window, Menu);
  293.                             
  294.                             if (!(CreateOrLayoutGadgets(scr, &FirstGad, &PianoGad, ChanLedGad, ww, wh, &Octaves)))
  295.                             {
  296.                                 Message("Couldn't create gadgets!",NULL);
  297.                             }
  298.                             else
  299.                             {
  300.                                 AddGList(Window,FirstGad,-1,-1,NULL);
  301.                                 RefreshGList(FirstGad,Window,NULL,-1);
  302.                                 
  303.                                 if (!(midi = CreateMidi(
  304.                                     MIDI_Name, "VU Meters",
  305.                                     MIDI_RecvSignal, SIGBREAKB_CTRL_E,
  306.                                     MIDI_MsgQueue,   500,
  307.                                     MIDI_ErrFilter, CMEF_All,
  308.                                     TAG_DONE)))
  309.                                 {
  310.                                     Message("Cannot create MIDI port!",NULL);
  311.                                 }
  312.                                 else
  313.                                 {
  314.                                     if (!(link = AddMidiLink(midi, MLTYPE_Receiver,
  315.                                         MLINK_Name, "VU Meter Link",
  316.                                         MLINK_Location, linkname,
  317.                                         MLINK_EventMask, CMF_Note|CMF_Mode,
  318.                                         MLINK_Comment,  "Piano Meter [Input]",
  319.                                         TAG_DONE)))
  320.                                     {
  321.                                         Message("Cannot create link to MIDI interface '%s'",NULL,linkname);
  322.                                     }
  323.                                     else
  324.                                     {
  325.                                         SPrintf(buffer, "Piano Meter [%s]", linkname);
  326.                                         SetWindowTitles(Window, buffer, (UBYTE*) ~0);
  327.                                         
  328.                                         MyTask = FindTask(NULL);
  329.                                         OldPri = MyTask->tc_Node.ln_Pri;
  330.                                         MyTask->tc_Node.ln_Pri = 10;
  331.                                         
  332.                                         MainLoop(linkname, Window, &FirstGad, &PianoGad, ChanLedGad, &midi, &link, &Octaves);
  333.                                         ReturnCode = RETURN_OK;
  334.                                         
  335.                                         MyTask->tc_Node.ln_Pri = OldPri;
  336.                                         
  337.                                         RemoveMidiLink(link);
  338.                                     }
  339.                                     DeleteMidi(midi);
  340.                                 }
  341.                                 
  342.                                 RemoveGList(Window,FirstGad,-1);
  343.                                 
  344.                                 DisposeObject(PianoGad);
  345.                                 PianoGad=NULL;
  346.                                 
  347.                                 for (i=0; i<16; i++)
  348.                                 {
  349.                                     DisposeObject(ChanLedGad[i]);
  350.                                     ChanLedGad[i]=NULL;
  351.                                 }
  352.                             }
  353.                             ClearMenuStrip(Window);
  354.                             
  355.                             FreeMenus(Menu);
  356.                         }
  357.                         CloseWindow(Window);
  358.                     }
  359.                 }
  360.                 FreeVisualInfo(VisualInfo);
  361.             }
  362.             UnlockPubScreen(NULL, scr);
  363.         }
  364.         _freeclasses();
  365.     }
  366.     return(ReturnCode);
  367. }
  368.  
  369.  
  370. #define XSPACING 4
  371. #define INTERSPACING 2
  372. #define YSPACING 4
  373.  
  374.  
  375. BOOL WindowLayout(struct Screen *scr, WORD *ww, WORD *wh, WORD *minw, WORD *minh, WORD *maxw, WORD *maxh, ULONG *Octaves)
  376. {
  377.     BOOL Success = FALSE;
  378.     
  379.     struct gpDomain gpd;
  380.     struct TagItem ti[2];
  381.     
  382.     WORD pw=0, ph=0, pmaxw=0;
  383.     WORD clw=0, clh=0;
  384.     
  385.     /* Get the domain of a ChanLed object */
  386.     gpd.MethodID  = GM_DOMAIN;
  387.     gpd.gpd_GInfo = NULL;
  388.     gpd.gpd_RPort = &scr->RastPort;
  389.     gpd.gpd_Which = GDOMAIN_NOMINAL;
  390.     ti[0].ti_Tag  = NULL;
  391.     gpd.gpd_Attrs = ti;
  392.     if (DoCustomClassMethod (cl_ChanLed, (Msg)&gpd) == 1)
  393.     {
  394.         clw = gpd.gpd_Domain.Width;
  395.         clh = gpd.gpd_Domain.Height;
  396.     }
  397.     
  398.     /* Get the domain of the Piano object */
  399.     gpd.MethodID  = GM_DOMAIN;
  400.     gpd.gpd_GInfo = NULL;
  401.     gpd.gpd_RPort = &scr->RastPort;
  402.     gpd.gpd_Which = GDOMAIN_NOMINAL;
  403.     ti[0].ti_Tag  = BOPA_Piano_Octaves;
  404.     ti[0].ti_Data = *Octaves;
  405.     ti[1].ti_Tag  = TAG_DONE;
  406.     gpd.gpd_Attrs = ti;
  407.     if (DoCustomClassMethod (cl_Piano, (Msg)&gpd) == 1)
  408.     {
  409.         pw = gpd.gpd_Domain.Width;
  410.         ph = gpd.gpd_Domain.Height;
  411.     }
  412.     
  413.     /* Get the maximum width of a Piano object (11 octaves) */
  414.     ti[0].ti_Data = 11;
  415.     if (DoCustomClassMethod (cl_Piano, (Msg)&gpd) == 1)
  416.     {
  417.         pmaxw = gpd.gpd_Domain.Width;
  418.     }
  419.     
  420.     /* Calculate window width and height*/
  421.     if (16*clw > pw) *ww = XSPACING+16*clw+XSPACING;
  422.         else *ww = XSPACING+pw+XSPACING;
  423.     *wh = YSPACING+clh+INTERSPACING+ph+YSPACING;
  424.     
  425.     /* Calculate minimum width and height */
  426.     *minw = XSPACING+16*clw+XSPACING;
  427.     *minh = *wh;
  428.     
  429.     /* Calculate maximum width and height */
  430.     *maxw = XSPACING+pmaxw+XSPACING;
  431.     *maxh = *wh;
  432.     
  433.     Success=TRUE;
  434.     
  435.     return(Success);
  436. }
  437.  
  438.  
  439.  
  440. BOOL CreateOrLayoutGadgets(struct Screen *scr, struct Gadget **FirstGad, struct Gadget **PianoGad, struct Gadget **ChanLedGad, WORD ww, WORD wh, ULONG *Octaves)
  441. {
  442.     BOOL Success = FALSE;
  443.     
  444.     struct gpDomain gpd;
  445.     struct TagItem ti[2];
  446.     
  447.     WORD pw=0, ph=0;
  448.     WORD clw=0, clh=0;
  449.     
  450.     ULONG gx, gy;
  451.     
  452.     UWORD i;
  453.     struct Gadget *prev;
  454.     
  455.     ULONG OldOctaves = 0;
  456.     
  457.     if (*PianoGad)
  458.     {
  459.         GetAttr(BOPA_Piano_Octaves, *PianoGad, &OldOctaves);
  460.     }
  461.     
  462.     /* Get the domain of a ChanLed object */
  463.     gpd.MethodID  = GM_DOMAIN;
  464.     gpd.gpd_GInfo = NULL;
  465.     gpd.gpd_RPort = &scr->RastPort;
  466.     gpd.gpd_Which = GDOMAIN_NOMINAL;
  467.     ti[0].ti_Tag  = NULL;
  468.     gpd.gpd_Attrs = ti;
  469.     if (DoCustomClassMethod (cl_ChanLed, (Msg)&gpd) == 1)
  470.     {
  471.         clw = gpd.gpd_Domain.Width;
  472.         clh = gpd.gpd_Domain.Height;
  473.     }
  474.     
  475.     /* Try to fit a piano as large as possible into the window */
  476.     
  477.     *Octaves = 11;
  478.     do
  479.     {
  480.         /* Get the domain of the Piano object */
  481.         gpd.MethodID  = GM_DOMAIN;
  482.         gpd.gpd_GInfo = NULL;
  483.         gpd.gpd_RPort = &scr->RastPort;
  484.         gpd.gpd_Which = GDOMAIN_NOMINAL;
  485.         ti[0].ti_Tag  = BOPA_Piano_Octaves;
  486.         ti[0].ti_Data = *Octaves;
  487.         ti[1].ti_Tag  = TAG_DONE;
  488.         gpd.gpd_Attrs = ti;
  489.         if (DoCustomClassMethod (cl_Piano, (Msg)&gpd) == 1)
  490.         {
  491.             pw = gpd.gpd_Domain.Width;
  492.             ph = gpd.gpd_Domain.Height;
  493.         }
  494.         
  495.         if (XSPACING+pw+XSPACING > ww) (*Octaves)--;
  496.         
  497.     } while (XSPACING+pw+XSPACING > ww);
  498.     
  499.     /* Dispose piano only when no. of octaves changed */
  500.     
  501.     if (*PianoGad)
  502.     {
  503.         if (*Octaves != OldOctaves)
  504.         {
  505.             DisposeObject(*PianoGad);
  506.             *PianoGad=NULL;
  507.         }
  508.     }
  509.     
  510.     /* Create and/or layout the gadgets */
  511.     
  512.     gx = (ULONG)((ww-pw)/2);
  513.     gy = (ULONG)((wh-clh-INTERSPACING-ph)/2)+clh+INTERSPACING;
  514.     
  515.     if (!(*PianoGad))
  516.     {
  517.         if (*FirstGad = *PianoGad = prev = (struct Gadget*)NewObject( cl_Piano, NULL,
  518.                 GA_Left, gx,
  519.                 GA_Top, gy,
  520.                 GA_Width, (ULONG)pw,
  521.                 GA_Height, (ULONG)ph,
  522.                 GA_Immediate,TRUE,
  523.                 GA_RelVerify,TRUE,
  524.                 GA_ID,100,
  525.                 BOPA_Piano_Octaves, *Octaves,
  526.                 TAG_END) )
  527.         {
  528.             Success=TRUE;
  529.         }
  530.     }
  531.     else
  532.     {
  533.         *FirstGad = prev = *PianoGad;
  534.         
  535.         SetAttrs(*PianoGad, 
  536.             GA_Left, gx,
  537.             GA_Top, gy,
  538.             GA_Width, (ULONG)pw,
  539.             GA_Height, (ULONG)ph,
  540.             TAG_END );
  541.         
  542.         Success = TRUE;
  543.     }
  544.     
  545.     if (Success)
  546.     {
  547.         for (i=0; i<16; i++)
  548.         {
  549.             gx = (ULONG)((ww-16*clw)/2)+i*clw;
  550.             gy = (ULONG)((wh-clh-YSPACING-ph)/2);
  551.             
  552.             if (!(ChanLedGad[i]))
  553.             {
  554.                 if (!(ChanLedGad[i] = prev = (struct Gadget*)NewObject( cl_ChanLed, NULL,
  555.                         GA_Left, gx, 
  556.                         GA_Top, gy,
  557.                         GA_Width, (ULONG)clw,
  558.                         GA_Height, (ULONG)clh,
  559.                         GA_Immediate,TRUE,
  560.                         GA_RelVerify,TRUE,
  561.                         GA_ID,i,
  562.                         BOPA_ChanLed_Channel, (ULONG)i+1,
  563.                         BOPA_ChanLed_Enabled, 1L,
  564.                         BOPA_ChanLed_Lighted, 0L,
  565.                         GA_Previous, prev,
  566.                         TAG_END)))
  567.                 {
  568.                     Success=FALSE;
  569.                     break;
  570.                 }
  571.             }
  572.             else
  573.             {
  574.                 SetAttrs(ChanLedGad[i], 
  575.                     GA_Left, gx,
  576.                     GA_Top, gy,
  577.                     GA_Width, (ULONG)clw,
  578.                     GA_Height, (ULONG)clh,
  579.                     GA_Previous, prev,
  580.                     TAG_END );
  581.                 
  582.                 prev = ChanLedGad[i];
  583.             }
  584.         }
  585.     }
  586.     
  587.     if (!Success)
  588.     {
  589.         if (*PianoGad)
  590.         {
  591.             DisposeObject(*PianoGad);
  592.             *PianoGad=NULL;
  593.         }
  594.         
  595.         for (i=0; i<16; i++)
  596.         {
  597.             if (ChanLedGad[i])
  598.             {
  599.                 DisposeObject(ChanLedGad[i]);
  600.                 ChanLedGad[i]=NULL;
  601.             }
  602.         }
  603.         
  604.         *FirstGad = NULL;
  605.     }
  606.     
  607.     return(Success);
  608. }
  609.  
  610.  
  611.  
  612. #define TAGSIZE 32
  613.  
  614. UWORD NoteArray[128];
  615. struct TagItem TagBuffer[TAGSIZE];
  616. UBYTE ChanUse[16];
  617.  
  618. void MainLoop(UBYTE *linkname, struct Window *Window, struct Gadget **FirstGad, struct Gadget **PianoGad, struct Gadget **ChanLedGad, struct MidiNode **midi, struct MidiLink **link, ULONG *Octaves)
  619. {
  620.     UWORD MidKey = (*Octaves/2)*12;
  621.     UWORD Mask = 0xffff;
  622.     
  623.     BOOL Active;
  624.     ULONG signals;
  625.     ULONG gotsignals;
  626.     struct IntuiMessage *imsg;
  627.     ULONG Cl;
  628.     UWORD Co;
  629.     APTR IA;
  630.     
  631.     UBYTE Err;
  632.     
  633.     struct TagItem *tagptr;
  634.     ULONG numtags;
  635.     
  636.     UBYTE NewLink[32];
  637.     UBYTE buffer[80];
  638.     
  639.     Active=TRUE;
  640.     
  641.     memset(NoteArray,0,sizeof(NoteArray));
  642.     memset(ChanUse  ,0,sizeof(ChanUse  ));
  643.     
  644.     while(Active)
  645.     {
  646.         signals = (1L<<Window->UserPort->mp_SigBit) | SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_E;
  647.         
  648.         gotsignals = Wait(signals);
  649.         
  650.         if (gotsignals & (1L<<Window->UserPort->mp_SigBit))
  651.         {
  652.             while(Active && (imsg=(struct IntuiMessage*)GetMsg(Window->UserPort)))
  653.             {
  654.                 Cl=imsg->Class;
  655.                 Co=imsg->Code;
  656.                 IA=imsg->IAddress;
  657.                 ReplyMsg((struct Message*)imsg);
  658.                 
  659.                 if (Cl==IDCMP_CLOSEWINDOW)
  660.                 {
  661.                     Active=FALSE;
  662.                     break;
  663.                 }
  664.                 
  665.                 if (Cl==IDCMP_GADGETDOWN)
  666.                 {
  667.                     UWORD ID = ((struct Gadget*)IA)->GadgetID;
  668.                     
  669.                     if (ID < 16)
  670.                     {
  671.                         ULONG flag;
  672.                         UWORD note;
  673.                         
  674.                         GetAttr(BOPA_ChanLed_Enabled, IA, &flag);
  675.                         
  676.                         if (flag)
  677.                             Mask |= (1<<ID);
  678.                         else
  679.                             Mask &= (~(1<<ID));
  680.                         
  681.                         tagptr = TagBuffer;
  682.                         numtags = 0;
  683.                         
  684.                         for (note=0;note<128;note++)
  685.                         {
  686.                             UWORD key = note-60+MidKey;
  687.                             
  688.                             if (key < 12* (*Octaves))
  689.                             {
  690.                                 if ((NoteArray[note] & Mask))
  691.                                 {
  692.                                     tagptr->ti_Tag  = BOPA_Piano_KeyState;
  693.                                     tagptr->ti_Data = (ULONG)(SETKEY|key);
  694.                                     tagptr++;numtags++;
  695.                                 }
  696.                                 else
  697.                                 {
  698.                                     tagptr->ti_Tag  = BOPA_Piano_KeyState;
  699.                                     tagptr->ti_Data = (ULONG)(CLEARKEY|key);
  700.                                     tagptr++;numtags++;
  701.                                 }
  702.                                 
  703.                                 if (numtags == TAGSIZE-1)
  704.                                 {
  705.                                     tagptr->ti_Tag = TAG_END;
  706.                                     SetGadgetAttrsA(*PianoGad,Window,NULL,TagBuffer);
  707.                                     tagptr = TagBuffer; numtags = 0;
  708.                                 }
  709.                             }
  710.                         }
  711.                         
  712.                         if (numtags)
  713.                         {
  714.                             tagptr->ti_Tag = TAG_END;
  715.                             SetGadgetAttrsA(*PianoGad,Window,NULL,TagBuffer);
  716.                             tagptr = TagBuffer; numtags = 0;
  717.                         }
  718.                     }
  719.                 }
  720.                 
  721.                 if (Cl==IDCMP_GADGETUP)
  722.                 {
  723.                 }
  724.                 
  725.                 if (Cl==IDCMP_SIZEVERIFY)
  726.                 {
  727.                 }
  728.                 
  729.                 if (Cl==IDCMP_NEWSIZE)
  730.                 {
  731.                     WORD ww = Window->Width  - Window->BorderLeft-Window->BorderRight ;
  732.                     WORD wh = Window->Height - Window->BorderTop -Window->BorderBottom;
  733.                     
  734.                     RemoveGList(Window,*FirstGad,-1);
  735.                     
  736.                     EraseRect(Window->RPort, 0, 0, ww-1, wh-1);
  737.                     
  738.                     if (!(CreateOrLayoutGadgets(Window->WScreen, FirstGad, PianoGad, ChanLedGad, ww, wh, Octaves)))
  739.                     {
  740.                         Message("Error during gadget layout!",NULL);
  741.                         Active=FALSE;
  742.                         break;
  743.                     }
  744.                     else
  745.                     {
  746.                         /* Gadgets have been re-created */
  747.                         /* Now set them to the desired state */
  748.                         /* even before redrawing */
  749.                         
  750.                         UBYTE chn;
  751.                         UWORD note;
  752.                         
  753.                         MidKey = (*Octaves/2)*12;
  754.                         
  755.                         for (chn=0;chn<16;chn++)
  756.                         {
  757.                             SetAttrs(ChanLedGad[chn], BOPA_ChanLed_Enabled, (ULONG)( (Mask & (1<<chn)) ? TRUE:FALSE ), TAG_DONE);
  758.                             SetAttrs(ChanLedGad[chn], BOPA_ChanLed_Lighted, (ULONG)( ( ChanUse[chn]  ) ? TRUE:FALSE ), TAG_DONE);
  759.                         }
  760.                         
  761.                         tagptr = TagBuffer;
  762.                         numtags = 0;
  763.                         
  764.                         for (note=0;note<128;note++)
  765.                         {
  766.                             UWORD key = note-60+MidKey;
  767.                             
  768.                             if (key < 12* (*Octaves))
  769.                             {
  770.                                 if ((NoteArray[note] & Mask))
  771.                                 {
  772.                                     tagptr->ti_Tag  = BOPA_Piano_KeyState;
  773.                                     tagptr->ti_Data = (ULONG)(SETKEY|key);
  774.                                     tagptr++;numtags++;
  775.                                 }
  776.                                 else
  777.                                 {
  778.                                     tagptr->ti_Tag  = BOPA_Piano_KeyState;
  779.                                     tagptr->ti_Data = (ULONG)(CLEARKEY|key);
  780.                                     tagptr++;numtags++;
  781.                                 }
  782.                                 
  783.                                 if (numtags == TAGSIZE-1)
  784.                                 {
  785.                                     tagptr->ti_Tag = TAG_END;
  786.                                     SetAttrsA(*PianoGad,TagBuffer);
  787.                                     tagptr = TagBuffer; numtags = 0;
  788.                                 }
  789.                             }
  790.                         }
  791.                         
  792.                         if (numtags)
  793.                         {
  794.                             tagptr->ti_Tag = TAG_END;
  795.                             SetAttrsA(*PianoGad,TagBuffer);
  796.                             tagptr = TagBuffer; numtags = 0;
  797.                         }
  798.                         
  799.                         AddGList(Window,*FirstGad,-1,-1,NULL);
  800.                         RefreshGList(*FirstGad,Window,NULL,-1);
  801.                     }
  802.                 }
  803.                 
  804.                 if (Cl==IDCMP_MENUPICK)
  805.                 {
  806.                     struct MenuItem *n;
  807.                     ULONG pick;
  808.                     
  809.                     while( (Co != MENUNULL) && Active)
  810.                     {
  811.                         n = ItemAddress( Window->MenuStrip, (ULONG)Co );
  812.                         pick = (ULONG) GTMENUITEM_USERDATA( n );
  813.                         
  814.                         switch(pick)
  815.                         {
  816.                             case Menu_Link:
  817.                             {
  818.                                 APTR listreq;
  819.                                 
  820.                                 if (!(listreq = AllocListRequest(
  821.                                     LISTREQ_Window, Window,
  822.                                     LISTREQ_TitleText, "Select input link",
  823.                                     TAG_DONE )))
  824.                                 {
  825.                                     Message("Couldn't allocate a list requester.",NULL);
  826.                                 }
  827.                                 else
  828.                                 {
  829.                                     if (linkname != NewLink)
  830.                                     {
  831.                                         strncpy(NewLink, (*link)->ml_Location->mcl_Node.ln_Name, sizeof(NewLink));
  832.                                         NewLink[sizeof(NewLink)-1] = 0;
  833.                                     }
  834.                                     
  835.                                     if (SelectCluster( listreq, NewLink, sizeof(NewLink), TAG_DONE ))
  836.                                     {
  837.                                         if (strcmp((*link)->ml_Location->mcl_Node.ln_Name,NewLink))
  838.                                         {
  839.                                             struct MidiLink *newlink;
  840.                                             
  841.                                             if (!(newlink = AddMidiLink(*midi, MLTYPE_Receiver,
  842.                                                 MLINK_Name, "VU Meter Link",
  843.                                                 MLINK_Location, NewLink,
  844.                                                 MLINK_EventMask, CMF_Note|CMF_Mode,
  845.                                                 MLINK_Comment,  "Piano Meter [Input]",
  846.                                                 TAG_DONE)))
  847.                                             {
  848.                                                 Message("Cannot create link to MIDI interface '%s'",NULL,NewLink);
  849.                                             }
  850.                                             else
  851.                                             {
  852.                                                 UWORD note;
  853.                                                 UBYTE chn;
  854.                                                 
  855.                                                 tagptr = TagBuffer;
  856.                                                 numtags = 0;
  857.                                                 
  858.                                                 RemoveMidiLink( *link );
  859.                                                 FlushMidi( *midi );
  860.                                                 
  861.                                                 *link = newlink;
  862.                                                 linkname = NewLink;
  863.                                                 
  864.                                                 SPrintf(buffer, "Piano Meter [%s]", linkname);
  865.                                                 SetWindowTitles(Window, buffer, (UBYTE*) ~0);
  866.                                                 
  867.                                                 for (note=0;note<128;note++)
  868.                                                 {
  869.                                                     for (chn=0;chn<16;chn++)
  870.                                                     {
  871.                                                         UWORD key = note-60+MidKey;
  872.                                                         UWORD cmsk = 1<<chn;
  873.                                                         
  874.                                                         if (NoteArray[note] & cmsk)
  875.                                                         {
  876.                                                             ChanUse[chn]--;
  877.                                                             if (!ChanUse[chn]) SetGadgetAttrs(ChanLedGad[chn], Window, NULL, BOPA_ChanLed_Lighted, FALSE, TAG_DONE);
  878.                                                             
  879.                                                             NoteArray[note] &= (~cmsk);
  880.                                                             
  881.                                                             if ((key < 12* (*Octaves)) && (Mask & cmsk) && (!(NoteArray[note] & Mask)))
  882.                                                             {
  883.                                                                 tagptr->ti_Tag  = BOPA_Piano_KeyState;
  884.                                                                 tagptr->ti_Data = (ULONG)(CLEARKEY|key);
  885.                                                                 tagptr++;numtags++;
  886.                                                                 
  887.                                                                 if (numtags == TAGSIZE-1)
  888.                                                                 {
  889.                                                                     tagptr->ti_Tag = TAG_END;
  890.                                                                     SetGadgetAttrsA(*PianoGad,Window,NULL,TagBuffer);
  891.                                                                     tagptr = TagBuffer; numtags = 0;
  892.                                                                 }
  893.                                                             }
  894.                                                         }
  895.                                                     }
  896.                                                 }
  897.                                                 if (numtags)
  898.                                                 {
  899.                                                     tagptr->ti_Tag = TAG_END;
  900.                                                     SetGadgetAttrsA(*PianoGad,Window,NULL,TagBuffer);
  901.                                                     tagptr = TagBuffer; numtags = 0;
  902.                                                 }
  903.                                             }
  904.                                         }
  905.                                     }
  906.                                     FreeListRequest(listreq);
  907.                                 }
  908.                             }
  909.                             break;
  910.                             
  911.                             case Menu_Save:
  912.                             {
  913.                                 Message("Save Config\nIsn't implemented... eeeh!","Damn");
  914.                             }
  915.                             break;
  916.                             
  917.                             case Menu_About:
  918.                             {
  919.                                 Message("Piano Meter\n© 1998 by Christian Buchner\nflowerp@eikon.e-technik.tu-muenchen.de","Cool");
  920.                             }
  921.                             break;
  922.                             
  923.                             case Menu_Quit:
  924.                             {
  925.                                 Active = FALSE;
  926.                             }
  927.                             break;
  928.                             
  929.                             case Menu_Release:
  930.                             {
  931.                                 UWORD note;
  932.                                 UBYTE chn;
  933.                                 
  934.                                 tagptr = TagBuffer;
  935.                                 numtags = 0;
  936.                                 
  937.                                 for (note=0;note<128;note++)
  938.                                 {
  939.                                     for (chn=0;chn<16;chn++)
  940.                                     {
  941.                                         UWORD key = note-60+MidKey;
  942.                                         UWORD cmsk = 1<<chn;
  943.                                         
  944.                                         if (NoteArray[note] & cmsk)
  945.                                         {
  946.                                             ChanUse[chn]--;
  947.                                             if (!ChanUse[chn]) SetGadgetAttrs(ChanLedGad[chn], Window, NULL, BOPA_ChanLed_Lighted, FALSE, TAG_DONE);
  948.                                             
  949.                                             NoteArray[note] &= (~cmsk);
  950.                                             
  951.                                             if ((key < 12* (*Octaves)) && (Mask & cmsk) && (!(NoteArray[note] & Mask)))
  952.                                             {
  953.                                                 tagptr->ti_Tag  = BOPA_Piano_KeyState;
  954.                                                 tagptr->ti_Data = (ULONG)(CLEARKEY|key);
  955.                                                 tagptr++;numtags++;
  956.                                                 
  957.                                                 if (numtags == TAGSIZE-1)
  958.                                                 {
  959.                                                     tagptr->ti_Tag = TAG_END;
  960.                                                     SetGadgetAttrsA(*PianoGad,Window,NULL,TagBuffer);
  961.                                                     tagptr = TagBuffer; numtags = 0;
  962.                                                 }
  963.                                             }
  964.                                         }
  965.                                     }
  966.                                 }
  967.                                 
  968.                                 if (numtags)
  969.                                 {
  970.                                     tagptr->ti_Tag = TAG_END;
  971.                                     SetGadgetAttrsA(*PianoGad,Window,NULL,TagBuffer);
  972.                                     tagptr = TagBuffer; numtags = 0;
  973.                                 }
  974.                             }
  975.                             break;
  976.                         }
  977.                         
  978.                         Co = n->NextSelect;
  979.                     }
  980.                 }
  981.             }
  982.         }
  983.         
  984.         if (Active && (gotsignals & SIGBREAKF_CTRL_E))
  985.         {
  986.             MidiMsg msg;
  987.             
  988.             tagptr = TagBuffer;
  989.             numtags = 0;
  990.             
  991.             while (GetMidi(*midi,&msg))
  992.             {
  993.                 if (noteon(&msg))
  994.                 {
  995.                     UBYTE chn  = msg.mm_Status & MS_ChanBits;
  996.                     UWORD note = msg.mm_Data1;
  997.                     UWORD key  = note-60+MidKey;
  998.                     UWORD cmsk = 1<<chn;
  999.                     
  1000.                     if (!(NoteArray[note] & cmsk))
  1001.                     {
  1002.                         if (!ChanUse[chn]) SetGadgetAttrs(ChanLedGad[chn], Window, NULL, BOPA_ChanLed_Lighted, TRUE, TAG_DONE);
  1003.                         ChanUse[chn]++;
  1004.                         
  1005.                         if ((key < 12* (*Octaves)) && (Mask & cmsk) && (!(NoteArray[note] & Mask)))
  1006.                         {
  1007.                             tagptr->ti_Tag  = BOPA_Piano_KeyState;
  1008.                             tagptr->ti_Data = (ULONG)(SETKEY|key);
  1009.                             tagptr++;numtags++;
  1010.                         }
  1011.                         
  1012.                         NoteArray[note] |= cmsk;
  1013.                     }
  1014.                 }
  1015.                 else
  1016.                 {
  1017.                     if (noteoff(&msg))
  1018.                     {
  1019.                         UBYTE chn  = msg.mm_Status & MS_ChanBits;
  1020.                         UWORD note = msg.mm_Data1;
  1021.                         UWORD key  = note-60+MidKey;
  1022.                         UWORD cmsk = 1<<chn;
  1023.                         
  1024.                         if (NoteArray[note] & cmsk)
  1025.                         {
  1026.                             ChanUse[chn]--;
  1027.                             if (!ChanUse[chn]) SetGadgetAttrs(ChanLedGad[chn], Window, NULL, BOPA_ChanLed_Lighted, FALSE, TAG_DONE);
  1028.                             
  1029.                             NoteArray[note] &= (~cmsk);
  1030.                             
  1031.                             if ((key < 12* (*Octaves)) && (Mask & cmsk) && (!(NoteArray[note] & Mask)))
  1032.                             {
  1033.                                 tagptr->ti_Tag  = BOPA_Piano_KeyState;
  1034.                                 tagptr->ti_Data = (ULONG)(CLEARKEY|key);
  1035.                                 tagptr++;numtags++;
  1036.                             }
  1037.                         }
  1038.                         
  1039.                     }
  1040.                     else
  1041.                     {
  1042.                         if (modemsg(&msg))
  1043.                         {
  1044.                             UBYTE chn  = msg.mm_Status & MS_ChanBits;
  1045.                             UBYTE mode = msg.mm_Data1;
  1046.                             UWORD note;
  1047.                             UWORD cmsk = 1<<chn;
  1048.                             
  1049.                             if (mode == MM_AllOff)
  1050.                             {
  1051.                                 for (note=0;note<128;note++)
  1052.                                 {
  1053.                                     UWORD key = note-60+MidKey;
  1054.                                     
  1055.                                     if (NoteArray[note] & cmsk)
  1056.                                     {
  1057.                                         ChanUse[chn]--;
  1058.                                         if (!ChanUse[chn]) SetGadgetAttrs(ChanLedGad[chn], Window, NULL, BOPA_ChanLed_Lighted, FALSE, TAG_DONE);
  1059.                                         
  1060.                                         NoteArray[note] &= (~cmsk);
  1061.                                         
  1062.                                         if ((key < 12* (*Octaves)) && (Mask & cmsk) && (!(NoteArray[note] & Mask)))
  1063.                                         {
  1064.                                             tagptr->ti_Tag  = BOPA_Piano_KeyState;
  1065.                                             tagptr->ti_Data = (ULONG)(CLEARKEY|key);
  1066.                                             tagptr++;numtags++;
  1067.                                             
  1068.                                             if (numtags == TAGSIZE-1)
  1069.                                             {
  1070.                                                 tagptr->ti_Tag = TAG_END;
  1071.                                                 SetGadgetAttrsA(*PianoGad,Window,NULL,TagBuffer);
  1072.                                                 tagptr = TagBuffer; numtags = 0;
  1073.                                             }
  1074.                                         }
  1075.                                     }
  1076.                                 }
  1077.                             }
  1078.                         }
  1079.                     }
  1080.                 }
  1081.                 
  1082.                 if (numtags == TAGSIZE-1)
  1083.                 {
  1084.                     tagptr->ti_Tag = TAG_END;
  1085.                     SetGadgetAttrsA(*PianoGad,Window,NULL,TagBuffer);
  1086.                     tagptr = TagBuffer; numtags = 0;
  1087.                 }
  1088.             }
  1089.             
  1090.             if (numtags)
  1091.             {
  1092.                 tagptr->ti_Tag = TAG_END;
  1093.                 SetGadgetAttrsA(*PianoGad,Window,NULL,TagBuffer);
  1094.                 tagptr = TagBuffer; numtags = 0;
  1095.             }
  1096.             
  1097.             if (Err = GetMidiErr(*midi))
  1098.             {
  1099.                 if (Err & CMEF_MsgErr)            Message("MIDI Error: MsgErr!",NULL);
  1100.                 if (Err & CMEF_BufferFull)        Message("MIDI Error: BufferFull!",NULL);
  1101.                 if (Err & CMEF_SysExFull)        Message("MIDI Error: SysExFull!",NULL);
  1102.                 if (Err & CMEF_ParseMem)        Message("MIDI Error: ParseMem!",NULL);
  1103.                 if (Err & CMEF_RecvErr)            Message("MIDI Error: RecvErr!",NULL);
  1104.                 if (Err & CMEF_RecvOverflow)    Message("MIDI Error: RecvOverflow!",NULL);
  1105.                 if (Err & CMEF_SysExTooBig)        Message("MIDI Error: SysExTooBig!",NULL);
  1106.             }
  1107.         }
  1108.         
  1109.         if (gotsignals & SIGBREAKF_CTRL_C)
  1110.         {
  1111.             Active=FALSE;
  1112.         }
  1113.     }
  1114. }
  1115.  
  1116.  
  1117.  
  1118. BOOL OpenLibs(void)
  1119. {
  1120.     BOOL Success=FALSE;
  1121.     
  1122.     SysBase = *((struct ExecBase**)(0x4));
  1123.     
  1124.     if (DOSBase=(struct DosLibrary*)OpenLibrary("dos.library",39L))
  1125.     {
  1126.         if (GfxBase=(struct GfxBase*)OpenLibrary("graphics.library",39L))
  1127.         {
  1128.             if (IntuitionBase=(struct IntuitionBase*)OpenLibrary("intuition.library",39L))
  1129.             {
  1130.                 if (GadToolsBase=OpenLibrary("gadtools.library", 39L))
  1131.                 {
  1132.                     if (UtilityBase=(struct Library*)OpenLibrary("utility.library",39L))
  1133.                     {
  1134.                         if (!(CamdBase=OpenLibrary("camd.library",0L)))
  1135.                         {
  1136.                             Message("This program requires camd.library!",NULL);
  1137.                         }
  1138.                         else
  1139.                         {
  1140.                             Success=TRUE;
  1141.                         }
  1142.                     }
  1143.                 }
  1144.             }
  1145.         }
  1146.     }
  1147.     if (!Success) CloseLibs();
  1148.     
  1149.     return(Success);
  1150. }
  1151.  
  1152.  
  1153. void CloseLibs(void)
  1154. {
  1155.     if (CamdBase)
  1156.     {
  1157.         CloseLibrary(CamdBase);
  1158.         CamdBase=NULL;
  1159.     }
  1160.     
  1161.     if (UtilityBase)
  1162.     {
  1163.         CloseLibrary(UtilityBase);
  1164.         UtilityBase=NULL;
  1165.     }
  1166.     
  1167.     if (GadToolsBase)
  1168.     {
  1169.         CloseLibrary(GadToolsBase);
  1170.         GadToolsBase=NULL;
  1171.     }
  1172.     
  1173.     if (IntuitionBase)
  1174.     {
  1175.         CloseLibrary((struct Library*)IntuitionBase);
  1176.         IntuitionBase=NULL;
  1177.     }
  1178.     
  1179.     if (GfxBase)
  1180.     {
  1181.         CloseLibrary((struct Library*)GfxBase);
  1182.         GfxBase=NULL;
  1183.     }
  1184.     
  1185.     if (DOSBase)
  1186.     {
  1187.         CloseLibrary((struct Library*)DOSBase);
  1188.         DOSBase=NULL;
  1189.     }
  1190. }
  1191.  
  1192.  
  1193. /*****************************************************************************/
  1194.  
  1195. LONG DoCustomClassMethod (struct IClass *cl, Msg msg)
  1196. {
  1197.     LONG (__asm *disp)(register __a0 Class *, register __a2 Object *, register __a1 Msg msg);
  1198.     disp = cl->cl_Dispatcher.h_Entry;
  1199.     return (*disp)(cl, (Object *) cl, msg);
  1200. }
  1201.  
  1202.  
  1203. /* Show a message to the user */
  1204.  
  1205. LONG __stdargs Message(UBYTE *Msg,UBYTE *Options,...)
  1206. {
  1207.     LONG retval;
  1208.     
  1209.     BOOL req = FALSE;
  1210.     
  1211.     va_list Arg;
  1212.     va_start(Arg,Options);
  1213.     
  1214.     // if (Options) if (strchr(Options,'|')) req = TRUE;
  1215.     if (Options) req = TRUE;
  1216.     
  1217.     if (IntuitionBase && (WBMode || req))
  1218.     {
  1219.         struct EasyStruct Req={sizeof(struct EasyStruct),0,"Piano Meter",0, NULL};
  1220.         
  1221.         if (!Options) Options = "I see";
  1222.         
  1223.         Req.es_TextFormat=Msg;
  1224.         Req.es_GadgetFormat=Options;
  1225.         
  1226.         retval=EasyRequestArgs(NULL,&Req,0,Arg);
  1227.     }
  1228.     else
  1229.     {
  1230.         if (DOSBase)
  1231.         {
  1232.             VPrintf(Msg,Arg);
  1233.             Printf("\n");
  1234.             
  1235.             retval=0;
  1236.         }
  1237.     }
  1238.     va_end(Arg);
  1239.     
  1240.     return(retval);
  1241. }
  1242.  
  1243.  
  1244. /* Standard Exit routine */
  1245.  
  1246. void __stdargs _XCEXIT(LONG lcode)
  1247. {
  1248.     Message("Task wants to exit, return code %ld\nHolding task!", NULL, lcode);
  1249.     Wait(0);
  1250. }
  1251.  
  1252.  
  1253.  
  1254. /* CAM Library stubs */
  1255.  
  1256. struct MidiNode *CreateMidi(Tag tag, ...)
  1257. {
  1258.     return CreateMidiA((struct TagItem *)&tag );
  1259. }
  1260.  
  1261. BOOL SetMidiAttrs(struct MidiNode *mi, Tag tag, ...)
  1262. {
  1263.     return SetMidiAttrsA(mi, (struct TagItem *)&tag );
  1264. }
  1265.  
  1266. struct MidiLink *AddMidiLink(struct MidiNode *mi, LONG type, Tag tag, ...)
  1267. {
  1268.     return AddMidiLinkA(mi, type, (struct TagItem *)&tag );
  1269. }
  1270.  
  1271. BOOL SetMidiLinkAttrs(struct MidiLink *mi, Tag tag, ...)
  1272. {
  1273.     return SetMidiLinkAttrsA(mi, (struct TagItem *)&tag );
  1274. }
  1275.